﻿using System;
using System.Windows.Controls;
using HOG.Controls;
using System.Windows.Markup;
using System.Windows;
using System.Windows.Resources;
using System.IO;
using System.Reflection;
using System.Net;
using System.IO.IsolatedStorage;
using System.Collections.Generic;
using BaseControls;
using System.Collections;
using System.Threading;
using System.Xml.Linq;
using System.Linq;
using HOG;
using ResourcesManager;
using System.Text.RegularExpressions;

namespace HOG
{
    public class ControlConstructor
    {
        public ControlConstructor()
        {
        }

        #region Fields       
        public event LevelConstructedDelegate Created;        
        public event StartConstructingDelegate StartCreating;        
        private BaseLevel baselevel;
        private Control control;
        public GameEventHandler GameEvent;//temporary value
        private WaitControl waitControl;
        private bool resourcesLoaded = false;//level resources like bitmap, sound...
        private string levelXaml = "";
        #endregion
        public BaseLevel GetActualLevel()
        {
            return baselevel;
        }
        public void LoadLevel(string fileName)//we need to download dynamic library and resources - everything asynchronous
        {
            resourcesLoaded = false;//reset resources flag
            if (StartCreating != null)
            {
                waitControl = new WaitControl();                
                StartCreating(waitControl);
            }
            try
            {                
                UriEx[] uriList = new UriEx[]{ new UriEx (new Uri(fileName, UriKind.Relative),this)};                
                ResourcesManager.ResourcesManager.DownloadFiles(uriList, (sender,stream) =>
                {
                    //level xaml has been downloaded                     
                    StreamReader rdr = new StreamReader(stream);
                    string xamlString = rdr.ReadToEnd();
                    UriEx[] assemblyList = GetAssembly(xamlString);
                    levelXaml = xamlString;                    
                    ResourcesManager.ResourcesManager.DownloadFiles(assemblyList, (sen,str) =>
                    {
                        AssemblyPart part = new AssemblyPart();
                        part.Load(str);                        
                    }, null, DownloadsComplete);
                }, null, null);
            }
            catch(Exception E)
            {
                MessageBox.Show("Error was raise in Resource download. Orginal message "+E.Message);
            }
        }
        private BaseLevel FindBaseLevel(Control control)
        {
           Grid grid = control.FindName("LayoutRoot") as Grid;
           foreach (UIElement element in grid.Children)
           {
               if (element is BaseLevel)
                   return element as BaseLevel;
           }
           return null;
        }
        private void LoadLevelControl(string xaml)
        {
            try
            {
                control = (Control)XamlReader.Load(xaml); //if we have xaml file and all assembly added download resources like bitmap, sound...            
                baselevel = FindBaseLevel(control);//Level doesn't need to be owner of all controls on level
                if (baselevel != null)
                {
                    baselevel.GameEvent += new GameEventHandler(GameEvent);
                    List<UriEx> resourcesUri = new List<UriEx>();
                    GetResources(baselevel, resourcesUri);
                    resourcesLoaded = true;
                    waitControl.max = resourcesUri.Count;
                    waitControl.Restart();
                    ResourcesManager.ResourcesManager.DownloadFiles(resourcesUri.ToArray(), BuildControlData, null, DownloadsComplete);
                }
                else
                    MessageBox.Show("Can't Find Base Level object or LayoutRoot controls");
            }
            catch (Exception E)
            {
                MessageBox.Show(E.Message);
            }
        }
        private void BuildControlData(object sender, Stream stream)
        {
            waitControl.ProcessChange();
            if (sender is BaseLevel)
            {
                BaseLevel level = sender as BaseLevel;                
                level.OnApplyTemplate();
                level.AssignStream(stream);
            }
            else
            {
                if (sender is BaseItem)
                {
                    BaseItem item = sender as BaseItem;
                    item.ApplyTemplate();
                    item.AssignStream(stream);
                }
                else
                {
                    if (sender is MediaElement)
                    {
                        MediaElement element = sender as MediaElement;
                        element.SetSource(stream);
                    }
                }
            }            
        }
        private void GetResources(BaseLevel aLevel, List<UriEx> resList)
        {
            if (aLevel.ResourcesNeeded != "")//for LevelBase background image
                resList.Add(new UriEx(new Uri(aLevel.ResourcesNeeded, UriKind.RelativeOrAbsolute),aLevel));
            foreach (UIElement item in aLevel.Children)
            {
                object res;
                if (item is BaseItem)
                    res = item.GetValue(BaseItem.ResourcesNeededProperty);
                else//if anything inherited from BaseItem have ResourcesNeeded property else try load resources property tag
                    res = item.GetValue(ResourcesManager.ResourcesManager.LoadResourcesProperty);
                if (res != null)                                           
                    resList.Add(new UriEx(new Uri(res as string, UriKind.RelativeOrAbsolute),item));                
            }
        }
        private UriEx[] GetAssembly(string xaml)
        {                          
            List<UriEx> assemblyList = new List<UriEx>();
            string pattern = @"assembly=(?<path>[a-z|_]*)""";            
            Regex reg = new Regex(pattern,RegexOptions.IgnoreCase);
            Match match = reg.Match(xaml);
            string path = "";
            while (match.Success)
            {
                path = match.Groups[0].Value;//match is string with assembly= part and " part
                int startIndex = path.IndexOf('=')+1;
                path = path.Substring(startIndex,path.IndexOf('"')-startIndex);
                assemblyList.Add(new UriEx(new Uri(path+".dll", UriKind.RelativeOrAbsolute), this));
                match = match.NextMatch();
            }
            return assemblyList.ToArray();
        }
        void DownloadsComplete()
        {            
            if (!resourcesLoaded)
                LoadLevelControl(levelXaml); //jeśli to wszystko to załaduj level                    
            else
                if (Created != null)                                    
                    Created(control);                
        }
        public IEnumerable<string> GetItems()
        {
            return baselevel.GetItems();
        }
    }
}
